package org.budo.support.logback.configurator;

import java.util.Iterator;
import java.util.List;

import org.slf4j.ILoggerFactory;
import org.slf4j.impl.StaticLoggerBinder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.filter.LevelFilter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.ConsoleAppender;
import lombok.extern.slf4j.Slf4j;

/**
 * @author lmw
 */
@Slf4j
public class DisableLogbackConsoleAppenderConfigurator implements ApplicationListener<ApplicationEvent> {
    private void handleConsoleAppender(ConsoleAppender consoleAppender) {
        if (!this.disableConsoleAppender()) {
            log.info("#28 not disableConsoleAppender, consoleAppender=" + consoleAppender);
            return;
        }

        // 禁用之前给出足够的提示
        log.info("#28 disableConsoleAppender, consoleAppender=" + consoleAppender);
        log.warn("#29 disableConsoleAppender, consoleAppender=" + consoleAppender);
        log.error("#30 disableConsoleAppender, consoleAppender=" + consoleAppender);
        System.out.println("#31 disableConsoleAppender, consoleAppender=" + consoleAppender);
        System.err.println("#32 disableConsoleAppender, consoleAppender=" + consoleAppender);

        // 禁用
        LevelFilter newFilter = new LevelFilter();
        newFilter.setLevel(Level.OFF);

        ((ConsoleAppender) consoleAppender).addFilter(newFilter);
    }

    /**
     * 是否禁止使用ConsoleAppender，默认返回false
     */
    protected Boolean disableConsoleAppender() {
        return false;
    }

    private void onContextRefreshedEvent(ContextRefreshedEvent event) {
        log.info("#54 onContextRefreshedEvent, event=" + event);

        ILoggerFactory loggerFactory = StaticLoggerBinder.getSingleton().getLoggerFactory();
        if (null == loggerFactory || !(loggerFactory instanceof LoggerContext)) {
            log.warn("#37 StaticLoggerBinder.loggerFactory is not logback.LoggerContext");
            return;
        }

        LoggerContext loggerContext = (LoggerContext) loggerFactory;
        List<Logger> loggers = loggerContext.getLoggerList();
        for (Logger logger : loggers) {
            Iterator<Appender<ILoggingEvent>> appenders = logger.iteratorForAppenders();
            while (appenders.hasNext()) {
                Appender<ILoggingEvent> appender = (Appender<ILoggingEvent>) appenders.next();
                if (appender instanceof ConsoleAppender) {
                    this.handleConsoleAppender((ConsoleAppender) appender);
                }
            }
        }
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent) {
            try {
                ApplicationContext applicationContext = ((ContextRefreshedEvent) event).getApplicationContext();
                ApplicationContext parent = applicationContext.getParent();
                if (null != parent) {
                    log.info("#83 return, applicationContext=" + applicationContext + ", parent=" + parent + ", event=" + event);
                    return;
                }

                this.onContextRefreshedEvent((ContextRefreshedEvent) event);
            } catch (Exception e) {
                log.error("#29 error", e);
            }
        }
    }
}